package com.oj.compile;

import com.oj.common.FileUtil;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.UUID;

@Component
public class Task {

    //通过一组常量约定临时文件的名字
    //表示所有临时文件所在的目录
    private  static  String WORK_DIR=null;
    //约定代码的类名
    private  static  String CLASS=null;
    //约定要编译的代码文件名
    private  static  String CODE=null;
    //存放编译结果出错的文件名
    private  static    String COMPILE_ERROR=null;
    //约定存放运行时的标准输出的文件名
    private  static   String STDOUT=null;
    //约定存放运行时的标准错误的文件名
    private  static   String STDERR=null;

public Task(){
    //在Java中UUID这个类生成一个UUID
    WORK_DIR="./tmp/" + UUID.randomUUID ().toString ()+"/";
    CLASS="Solution";
    CODE=WORK_DIR+"Solution.java";
    COMPILE_ERROR=WORK_DIR+"compileError.txt";
    STDOUT=WORK_DIR+"stdout.txt";
    STDERR=WORK_DIR+"stderr.txt";
}

    //这个Task类提供的核心方法，就叫做compileAndRun，编译+运行的意思
    //参数：要编译运行的Java源代码
    //返回值：表示编译运行的结果 ，比如编译出错啦，运行出错啦，运行正确，超时啦

    public  Answer compileAndRun(Question question) throws FileNotFoundException {
        Answer answer=new Answer ();
        //0准备好用来临时存放文件的目录
        File workDir=new File (WORK_DIR);
        if(!workDir.exists ()){
            //创建多级目录
            workDir.mkdirs ();
        }
        //进行安全性判定
        //现在待定不写
        //1就需要先把question的code写到一个Solution.java文件中
        FileUtil.writeFile (CODE,question.getCode ());

        //2、创建子进程、调用javac进行编译. 但是编译的时候需要.java文件，现在是String提供的代码

        //期间如果编译出错了，javac就会把错误信息写到到stderr中，因此可以用一个专门的文件来保存，compileErroe.txt
        String compileCmd=String.format ("javac -encoding utf8 %s -d %s",CODE,WORK_DIR);
        System.out.println ("编译命令："+ compileCmd);
        CommandUtil.run (compileCmd,null,COMPILE_ERROR);
        String compileError=FileUtil.readFile (COMPILE_ERROR);
        if(!compileError.equals ("")){
            //错误文件里不是空的，编译出错了！
            System.out.println ("编译出错!");
            answer.setError (1);
            answer.setReason (compileError);
            return answer;
        }
        //下面是编译正确的逻辑
        //3、创建子进程，调用java命令并执行
        // 运行程序的时候，也会把Java子进程的标准输出和标准错误获取到stdout.txt,stderr.txt
        String runCmd=String.format ("java -classpath %s %s",WORK_DIR,CLASS);
        System.out.println ("运行命令： "+runCmd);
        CommandUtil.run (runCmd,STDOUT,STDERR);
        String runError=FileUtil.readFile (STDERR);
        if(!runError.equals ("")){
            System.out.println ("运行出错!");
            answer.setError (2);
            answer.setReason (runError);
            return answer;
        }
        //4、父进程获取到刚才编译执行的结果，并打包成answer对象
        answer.setError (0);
        answer.setStdout (FileUtil.readFile (STDOUT));
        //编译运行的结果，就通过刚才约定的这几个文件来进行获取即可
        return answer;
    }

    public static void main (String[] args) throws FileNotFoundException {
        Task task=new Task ();
        Question question=new Question ();
        question.setCode ("public class Solution {\n" +
                "    public static void main(String[] args) {\n" +
                "        System.out.println(\"hello world\");\n" +
                "    }\n" +
                "}\n");
        Answer answer=task.compileAndRun (question);
        System.out.println (answer);
    }

}
